
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GLES/gl.h> /* For NDK*/
#include <android/log.h>
#include "utils.h"
#include "jade.h"


#define CALC_UVS(x, y, z, u, v) \
        vx = x; \
        vy = y; \
        vz = z; \
        mag = (float)sqrt(SQR(vx)+SQR(vy)+SQR(vz)); \
        vx /= mag;  \
        vy /= mag;  \
        vz /= mag;  \
        u = (float)(atan2(vx, vz)/(M_PI * 2)) + 0.5f;    \
        v = (float)(asinf(vy) / M_PI) + 0.5f;


jade_skydome_t *jade_skydome_create (int radius, float dtheta, float dphi) {

    jade_skydome_t *skydome = NULL;
    int vt_idx = 0, uv_idx = 0;
    float vx, vy, vz, mag;
    float *vertices0 = NULL, *uvs0 = NULL;

    float vertices[12];
    float uvs[8];
    float phi;
    float theta;
    float phi0;
    float theta0;



    skydome = (jade_skydome_t *)malloc (sizeof (jade_skydome_t));
    if (skydome == NULL)
        return NULL;

    skydome->mesh = jade_mesh_create ();

    //calc triangle counts
    int num_vertices = (int)((360 / dtheta) * ((int)(90 / dphi) + 1) * 2);
    jade_mesh_set_triangle_num (skydome->mesh, num_vertices);

    vertices0 = (float *) malloc(num_vertices * 9 * sizeof(float));
    uvs0 = (float *) malloc(num_vertices * 6 * sizeof(float));

    for (phi = 0.0f; phi <= 90.0f; phi += dphi) {
        for (theta = -180.0f; theta < 180.0f; theta += dtheta) {

            phi0 = phi + dphi;
            theta0 = theta + dtheta;

            //point 0
            vertices[0] = (float) (radius * sinf(DTOR * theta) * cosf(DTOR * phi));
            vertices[1] = (float) (radius * cosf(DTOR * theta) * cosf(DTOR * phi));
            vertices[2] = (float) (radius * sinf(DTOR * phi));

            //LOGD ("v[0] = %f, v[1] = %f, v[2] = %f\n", vertices[0], vertices[1], vertices[2]);

            CALC_UVS(vertices[0], vertices[1], vertices[2], uvs[0], uvs[1]);

            //point 1
            vertices[3] = (float) (radius * sinf(DTOR * theta) * cosf(DTOR * (phi + dphi)));
            vertices[4] = (float) (radius * cosf(DTOR * theta) * cosf(DTOR * (phi + dphi)));
            vertices[5] = (float) (radius * sinf(DTOR * (phi + dphi)));

            CALC_UVS(vertices[3], vertices[4], vertices[5], uvs[2], uvs[3]);

            //LOGD ("v[3] = %f, v[4] = %f, v[5] = %f\n", vertices[3], vertices[4], vertices[5]);

            //point 2
            vertices[6] = (float) (radius * sinf(DTOR * theta0) * cosf(DTOR * phi0));
            vertices[7] = (float) (radius * cosf(DTOR * theta0) * cosf(DTOR * phi0));
            vertices[8] = (float) (radius * sinf(DTOR * phi0));

            //LOGD ("v[6] = %f, v[7] = %f, v[8] = %f\n", vertices[6], vertices[7], vertices[8]);

            CALC_UVS(vertices[6], vertices[7], vertices[8], uvs[4], uvs[5]);

            //point 3
            vertices[9] = (float) (radius * sinf(DTOR * theta0) * cosf(DTOR * (phi0 + dphi)));
            vertices[10] = (float) (radius * cosf(DTOR * theta0) * cosf(DTOR * (phi0 + dphi)));
            vertices[11] = (float) (radius * sinf(DTOR * (phi0 + dphi)));

            //LOGD ("v[9] = %f, v[10] = %f, v[11] = %f\n", vertices[9], vertices[20], vertices[11]);

            CALC_UVS(vertices[9], vertices[10], vertices[11], uvs[6], uvs[7]);
            //printf("uvs:%.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f, %.4f\n", uvs[0], uvs[1], uvs[2], uvs[3], uvs[4], uvs[5], uvs[6], uvs[7]);
            //triangle 0 vertices & uvs of F3D skydome {0, 1, 2}
            vertices0[vt_idx++] = vertices[0];
            vertices0[vt_idx++] = vertices[1];
            vertices0[vt_idx++] = vertices[2];

            uvs0[uv_idx++] = uvs[0];
            uvs0[uv_idx++] = uvs[1];

            vertices0[vt_idx++] = vertices[3];
            vertices0[vt_idx++] = vertices[4];
            vertices0[vt_idx++] = vertices[5];

            uvs0[uv_idx++] = uvs[2];
            uvs0[uv_idx++] = uvs[3];

            vertices0[vt_idx++] = vertices[6];
            vertices0[vt_idx++] = vertices[7];
            vertices0[vt_idx++] = vertices[8];

            uvs0[uv_idx++] = uvs[4];
            uvs0[uv_idx++] = uvs[5];

            //triangle 0 vertices & uvs of F3D skydome {1, 2, 3}
            vertices0[vt_idx++] = vertices[3];
            vertices0[vt_idx++] = vertices[4];
            vertices0[vt_idx++] = vertices[5];

            uvs0[uv_idx++] = uvs[2];
            uvs0[uv_idx++] = uvs[3];

            vertices0[vt_idx++] = vertices[6];
            vertices0[vt_idx++] = vertices[7];
            vertices0[vt_idx++] = vertices[8];

            uvs0[uv_idx++] = uvs[4];
            uvs0[uv_idx++] = uvs[5];

            vertices0[vt_idx++] = vertices[9];
            vertices0[vt_idx++] = vertices[10];
            vertices0[vt_idx++] = vertices[11];

            uvs0[uv_idx++] = uvs[6];
            uvs0[uv_idx++] = uvs[7];

        }
    }

    jade_mesh_set_vertices (skydome->mesh, vertices0, num_vertices * 9 * sizeof(float));
    jade_mesh_set_uvs (skydome->mesh, uvs0, num_vertices * 6 * sizeof(float));

    FREEANDNULL(vertices0);
    FREEANDNULL(uvs0);
#ifdef DEBUG
    printf("skydome::uv_idx = %d\n", uv_idx);
#endif
    //after set m_enabled to true, so model can render it
    jade_mesh_set_position (skydome->mesh, 0.0f, (float)(-radius * sinf(DTOR * dphi)), 0.0f);
    jade_mesh_set_rotate (skydome->mesh, -90.0f, 0.0f, 0.0f);
#ifdef DEBUG
    printf("Generate Skydome OK!\n");
#endif

    return skydome;

}

void jade_skydome_destroy (jade_skydome_t *skydome) {

    if (skydome->mesh != NULL)
        jade_mesh_destroy (skydome->mesh);

    FREEANDNULL (skydome);

    return;
}


void jade_skydome_set_texture_id (jade_skydome_t *skydome, GLint textureId) {

    jade_mesh_set_texture_id (skydome->mesh, textureId);

    return;
}

void jade_skydome_set_position (jade_skydome_t *skydome, GLfloat x, GLfloat y, GLfloat z) {

    LOGD ("jade_skydome_set_position: x = %f, y = %f, z = %f.\n", x, y, z);

#ifdef FLOAT_ARG_FAIL
    jade_mesh_set_position (skydome->mesh, -10.0f, -2.0f, -3.0f);
#else
    jade_mesh_set_position (skydome->mesh, x, y, z);
#endif    

    return;
}


void jade_skydome_set_rotate (jade_skydome_t *skydome, GLfloat x, GLfloat y, GLfloat z) {

    jade_mesh_set_rotate (skydome->mesh, x, y, z);

    return;
}

void jade_skydome_render (jade_skydome_t *skydome) {

    if (skydome->mesh != NULL)
        jade_mesh_render (skydome->mesh);

}


